<template>
  <MoveablePanel class="select-panel" :width="200" :height="360"
    :title="`选择（${activeElementIdList.length}/${currentSlide.elements.length}）`" :left="-270" :top="90" @close="close()">
    <div class="handler" v-if="elements.length">
      <div class="btns">
        <Button size="small" style="margin-right: 5px;" @click="showAll()">全部显示</Button>
        <Button size="small" @click="hideAll()">全部隐藏</Button>
      </div>
      <div class="icon-btns" v-if="handleElement">
        <IconDown class="icon-btn" @click="orderElement(handleElement!, ElementOrderCommands.UP)" />
        <IconUp class="icon-btn" @click="orderElement(handleElement!, ElementOrderCommands.DOWN)" />
      </div>
    </div>
    <div class="element-list">
      <template v-for="item in elements" :key="item.id">
        <div class="group-els" v-if="item.type === 'group'">
          <div class="group-title">组合</div>
          <div class="item" :class="{
            'active': activeElementIdList.includes(groupItem.id),
            'group-active': activeGroupElementId.includes(groupItem.id),
          }" v-for="groupItem in item.elements" :key="groupItem.id" @click="selectGroupEl(item, groupItem.id)"
            @dblclick="enterEdit(groupItem.id)">
            <input :id="`input-${groupItem.id}`" :value="groupItem.name || ELEMENT_TYPE_ZH[groupItem.type]" class="input"
              type="text" v-if="editingElId === groupItem.id" @blur="$event => saveElementName($event, groupItem.id)"
              @keydown.enter="$event => saveElementName($event, groupItem.id)">
            <div v-else class="name">{{ groupItem.name || ELEMENT_TYPE_ZH[groupItem.type] }}</div>
            <div class="icons">
              <IconPreviewClose style="font-size: 17px;" @click.stop="hideElement(groupItem.id)"
                v-if="hiddenElementIdList.includes(groupItem.id)" />
              <IconPreviewOpen style="font-size: 17px;" @click.stop="hideElement(groupItem.id)" v-else />
            </div>
          </div>
        </div>
        <div class="item" :class="{ 'active': activeElementIdList.includes(item.id) }" v-else @click="selectEl(item.id)"
          @dblclick="enterEdit(item.id)">
          <input :id="`input-${item.id}`" :value="item.name || ELEMENT_TYPE_ZH[item.type]" class="input" type="text"
            v-if="editingElId === item.id" @blur="$event => saveElementName($event, item.id)"
            @keydown.enter="$event => saveElementName($event, item.id)">
          <div v-else class="name">{{ item.name || ELEMENT_TYPE_ZH[item.type] }}</div>
          <div class="icons">
            <IconPreviewClose style="font-size: 17px;" @click.stop="hideElement(item.id)"
              v-if="hiddenElementIdList.includes(item.id)" />
            <IconPreviewOpen style="font-size: 17px;" @click.stop="hideElement(item.id)" v-else />
          </div>
        </div>
      </template>
    </div>
  </MoveablePanel>
</template>

<script lang="ts" setup>
import { computed, nextTick, ref } from 'vue'
import { storeToRefs } from 'pinia'
import { useMainStore } from '@/store/main'
import { useSlidesStore } from '@/store/slides'
import { PPTElement } from '@/types/slides'
import { ELEMENT_TYPE_ZH } from '@/configs/element'
import useOrderElement from '@/hooks/useOrderElement'
import { ElementOrderCommands } from '@/types/edit'

import MoveablePanel from '@/components/MoveablePanel.vue'
import { Button } from 'ant-design-vue'

const slidesStore = useSlidesStore()
const mainStore = useMainStore()
const { currentSlide } = storeToRefs(slidesStore)
const { handleElement, handleElementId, activeElementIdList, activeGroupElementId, hiddenElementIdList } = storeToRefs(mainStore)

const { orderElement } = useOrderElement()

interface GroupElements {
  type: 'group'
  id: string
  elements: PPTElement[]
}
type ElementItem = PPTElement | GroupElements

const elements = computed<ElementItem[]>(() => {
  const _elements: ElementItem[] = []

  for (const el of currentSlide.value.elements) {
    if (el.groupId) {
      const lastItem = _elements[_elements.length - 1]

      if (lastItem && lastItem.type === 'group' && lastItem.id && lastItem.id === el.groupId) {
        lastItem.elements.push(el)
      }
      else _elements.push({ type: 'group', id: el.groupId, elements: [el] })
    }
    else _elements.push(el)
  }

  return _elements
})

const selectGroupEl = (item: GroupElements, id: string) => {
  if (handleElementId.value === id) return
  if (hiddenElementIdList.value.includes(id)) return

  const idList = item.elements.map(el => el.id)
  mainStore.setActiveElementIdList(idList)
  mainStore.setHandleElementId(id)
  nextTick(() => mainStore.setActiveGroupElementId(id))
}

const selectEl = (id: string) => {
  if (handleElementId.value === id) return
  if (hiddenElementIdList.value.includes(id)) return

  mainStore.setActiveElementIdList([id])
}

const hideElement = (id: string) => {
  if (hiddenElementIdList.value.includes(id)) {
    mainStore.setHiddenElementIdList(hiddenElementIdList.value.filter(item => item !== id))
  }
  else mainStore.setHiddenElementIdList([...hiddenElementIdList.value, id])

  if (activeElementIdList.value.includes(id)) mainStore.setActiveElementIdList([])
}

const showAll = () => {
  const currentSlideElIdList = currentSlide.value.elements.map(item => item.id)
  const needHiddenElementIdList = hiddenElementIdList.value.filter(item => !currentSlideElIdList.includes(item))
  mainStore.setHiddenElementIdList(needHiddenElementIdList)
}
const hideAll = () => {
  const currentSlideElIdList = currentSlide.value.elements.map(item => item.id)
  mainStore.setHiddenElementIdList([...hiddenElementIdList.value, ...currentSlideElIdList])
  if (activeElementIdList.value.length) mainStore.setActiveElementIdList([])
}

const editingElId = ref('')

const saveElementName = (e: FocusEvent | KeyboardEvent, id: string) => {
  const name = (e.target as HTMLInputElement).value
  slidesStore.updateElement({ id, props: { name } })
  editingElId.value = ''
}

const enterEdit = (id: string) => {
  editingElId.value = id
  nextTick(() => {
    const inputRef = document.querySelector(`#input-${id}`) as HTMLInputElement
    inputRef.focus()
  })
}

const close = () => {
  mainStore.setSelectPanelState(false)
}
</script>

<style lang="scss" scoped>
.select-panel {
  height: 100%;
  font-size: 12px;
  user-select: none;
}

.handler {
  height: 24px;
  margin-bottom: 8px;
  display: flex;
  align-items: center;
  justify-content: space-between;

  .icon-btns {
    height: 100%;
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: flex-end;
  }

  .icon-btn {
    width: 16px;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;

    &:hover {
      color: $themeColor;
    }
  }
}

.element-list {
  height: calc(100% - 32px);
  padding-right: 10px;
  margin-right: -10px;
  overflow: auto;
}

.item {
  padding: 5px;
  font-size: 12px;
  border-radius: $borderRadius;
  display: flex;
  align-items: center;
  cursor: pointer;

  &.active {
    background-color: rgba($color: $themeColor, $alpha: .1);
  }

  &.group-active {
    background-color: rgba($color: $themeColor, $alpha: .2);
  }

  &:hover {
    background-color: rgba($color: $themeColor, $alpha: .25);
  }

  .name {
    height: 18px;
    line-height: 18px;
    flex: 1;
    @include ellipsis-oneline();
  }

  .icons {
    width: 20px;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-left: 5px;
  }
}

.group-els {
  padding: 5px 0;

  .group-title {
    margin-bottom: 5px;
    padding: 0 5px;
  }

  .item {
    margin-left: 15px;
  }
}

.input {
  width: 100%;
  height: 18px;
  line-height: 18px;
  border: 0;
  outline: 0;
  padding-left: 0;
  padding-right: 0;
  flex: 1;
}
</style>